package com.example.gaojt.androiddemo.myDraw;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;

import junit.framework.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by bingo on 17-7-12.\
 */

public class CleanProcessView extends View {

    private static final int DEFAULT_RADIUS_DP = 100;
    private static final int DEFAULT_BIG_TEXT_DP = 48;
    private static final int DEFAULT_SMALL_TEXT_DP = 14;
    private static final int DEFAULT_BOTTOM_TEXT_DP = 20;
    private static final float DEFAULT_CIRCLE_STROKE_DP = 1.5f;
    private static final int DEFAULT_RIGHT_DP = 6;
    private static final int DEFAULT_BALL_MIN_RADIUS_DP = 10;
    private static final int DEFAULT_BALL_MAX_RADIUS_DP = 18;
    private static final int MSG_CLEANING = 1;
    private static final int MSG_CLEAN_ANIM_FINISH = 2;
    private static final int MSG_QUITE = 3;

    private Paint mFillCirclePaint;
    private Paint mStrokeCirclePaint;
    private Paint mBigTextPaint;
    private Paint mSmallTextPaint;
    private Paint mRightPaint;
    private Paint mBallPaint;
    private Paint mAlphaPaint = new Paint();

    private float mBigTextSize;
    private float mSmallTextSize;
    private float mBottomTextSize;
    private float mBallMinRadius; // 球的最小半径
    private float mBallMaxRadius; // 球的最大半径

    private RectF mBigTextRect = new RectF();
    private RectF mUnitTextRect = new RectF();
    private RectF mSmallTextRect = new RectF();

    private RectF mCircleRect = new RectF();
    private RectF mBottomTextRect = new RectF();
    private RectF mBitmapRect = new RectF();
    private Rect mBitmapSrcRect = new Rect();

    private int mBackgroundColor = 0xFF2296F3; // 自定義
    private ArcAnimation mArcAnimation;
    private List<BallAnimation> mBallAnimationList = new ArrayList<>();
    private CleanViewCallback mListener;

    private static final int STATE_INVALID = -1;
    private static final int STATE_NORMAL = 0;
    private static final int STATE_CLEANING = 1;
    private static final int STATE_CLEANED = 2;
    private static final int STATE_NOT_CLEAN = 3;
    private static final int STATE_QUIT = 4;

    private int mState = STATE_NORMAL;

    private ArrayList<BallAnimation> mDelTemp = new ArrayList<>();
    private int mWidth, mHeight;
    private int mRadius = 300;
    private static final int BALL_LENGTH = 10;
    private Ball[] mBalls = new Ball[BALL_LENGTH];
    private Handler mHandler;
    private String mBigText = "100.0";
    private String mUnitText = "MB ";
    private String mSmallText = "cleaning";
    private String mBottomText = "Cleaned 230M";
    private Bitmap mShadowBitmap; // 阴影图片

    private QuitAnimation mQuitAnim;

    public CleanProcessView(Context context) {
        this(context, null);
    }

    public CleanProcessView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CleanProcessView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initCustomViewParams(context, attrs);
        init();
    }

    private void initCustomViewParams(Context context, @Nullable AttributeSet attrs) {
        // TypedArray typedArray = null;
        // try {
        // typedArray = context.obtainStyledAttributes(attrs, R.styleable.CleanProcessView);
        // } finally {
        // if (typedArray != null) {
        // typedArray.recycle();
        // }
        // }
    }

    private void init() {
        initPaint();
        initHandler();
    }

    private void initPaint() {
        DisplayMetrics metrics = getResources().getDisplayMetrics();

        mRadius = (int) convertDpToPixel(DEFAULT_RADIUS_DP, metrics);
        mBigTextSize = convertDpToPixel(DEFAULT_BIG_TEXT_DP, metrics);
        mSmallTextSize = convertDpToPixel(DEFAULT_SMALL_TEXT_DP, metrics);
        mBottomTextSize = convertDpToPixel(DEFAULT_BOTTOM_TEXT_DP, metrics);
        mBallMinRadius = convertDpToPixel(DEFAULT_BALL_MIN_RADIUS_DP, metrics);
        mBallMaxRadius = convertDpToPixel(DEFAULT_BALL_MAX_RADIUS_DP, metrics);

        mFillCirclePaint = new Paint();
        mFillCirclePaint.setAntiAlias(true);
        mFillCirclePaint.setColor(mBackgroundColor);
        mFillCirclePaint.setStyle(Paint.Style.FILL);

        mStrokeCirclePaint = new Paint();
        mStrokeCirclePaint.setAntiAlias(true);
        mStrokeCirclePaint.setColor(Color.WHITE);
        mStrokeCirclePaint.setStyle(Paint.Style.STROKE);
        mStrokeCirclePaint.setStrokeWidth(convertDpToPixel(DEFAULT_CIRCLE_STROKE_DP, metrics));

        mBigTextPaint = new Paint();
        mBigTextPaint.setAntiAlias(true);
        mBigTextPaint.setColor(Color.WHITE);
        mBigTextPaint.setStyle(Paint.Style.FILL);
        mBigTextPaint.setTextSize(mBigTextSize);
        mBigTextPaint.setTextAlign(Paint.Align.CENTER);// 居中

        mSmallTextPaint = new Paint();
        mSmallTextPaint.setAntiAlias(true);
        mSmallTextPaint.setColor(Color.WHITE);
        mSmallTextPaint.setStyle(Paint.Style.FILL);
        mSmallTextPaint.setTextSize(mSmallTextSize);
        mSmallTextPaint.setColor(0xb2ffffff);
        mSmallTextPaint.setTextAlign(Paint.Align.CENTER);// 居中

        mRightPaint = new Paint();
        mRightPaint.setAntiAlias(true);
        mRightPaint.setColor(Color.WHITE);
        mRightPaint.setStyle(Paint.Style.STROKE);
        mRightPaint.setStrokeWidth(convertDpToPixel(DEFAULT_RIGHT_DP, metrics));

        mBallPaint = new Paint();
        mBallPaint.setAntiAlias(true);
        mBallPaint.setColor(Color.WHITE);
        mBallPaint.setStyle(Paint.Style.FILL);
        mBallPaint.setStrokeWidth(10);

        mArcAnimation = new ArcAnimation(0, 360);
        mArcAnimation.setDuration(1000);
        mArcAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        mArcAnimation.start();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        int radius = mRadius;
        int centerX = w / 2;
        int centerY = h / 2;

        resetCircleRect(radius, centerX, centerY);
        resetBottomTextRect(radius, centerX, centerY);
        resetBitmapRect(radius, centerX, centerY);
        resetShadowBitmap(radius);


        mQuitAnim = new QuitAnimation();
        mQuitAnim.setDuration(800);
        mQuitAnim.start();
        initBalls(centerX, centerY, radius);
    }

    private void resetShadowBitmap(int radius) {
        int shadowRadius = 150;
        int bmpWidth = (radius + shadowRadius) * 2;
        int bmpHHeight = (radius + shadowRadius) * 2;

        Paint shadowCirclePaint = new Paint();
        shadowCirclePaint.setColor(Color.WHITE);
        shadowCirclePaint.setStyle(Paint.Style.FILL);
        shadowCirclePaint.setShadowLayer(150, 0, 0, 0xffffffff);
        Bitmap shadowBitmap = Bitmap.createBitmap(bmpWidth, bmpHHeight, Bitmap.Config.ARGB_4444);
        Canvas canvasTemp = new Canvas(shadowBitmap);
        mShadowBitmap = shadowBitmap;
        canvasTemp.drawCircle(bmpWidth / 2, bmpHHeight / 2, radius, shadowCirclePaint);
        mBitmapSrcRect.set(0, 0, bmpWidth, bmpHHeight);
    }

    private void resetBitmapRect(int radius, int centerX, int centerY) {
        mBitmapRect.left = (float) (centerX - radius - 150);
        mBitmapRect.top = (float) (centerY - radius - 150);
        mBitmapRect.right = (float) (centerX + radius + 150);
        mBitmapRect.bottom = (float) (centerY + radius + 150);
    }

    private void resetBottomTextRect(int radius, int centerX, int centerY) {
        mBottomTextRect.left = (float) (centerX - radius);
        mBottomTextRect.top = (float) (centerY + radius * 1.2);
        mBottomTextRect.right = (float) (centerX + radius);
        mBottomTextRect.bottom = (float) (centerY + radius * 1.4);
    }

    private void resetCircleRect(int radius, int centerX, int centerY) {
        mCircleRect.left = (float) (centerX - radius);
        mCircleRect.top = (float) (centerY - radius);
        mCircleRect.right = (float) (centerX + radius);
        mCircleRect.bottom = (float) (centerY + radius);
    }

    private void initBalls(int centerX, int centerY, int radius) {
        Ball ball = new Ball(radius / 2, centerX, centerY, angle2radian(100), 1000, new AccelerateInterpolator());
        ball.ballRadius = mBallMaxRadius;
        ball.alpa = 240;
        mBalls[0] = ball;

        ball = new Ball(-radius / 2, centerX, centerY, angle2radian(100), 800, new AccelerateInterpolator());
        ball.ballRadius = mBallMaxRadius;
        ball.alpa = 240;
        mBalls[1] = ball;

        ball = new Ball(radius / 2, centerX - radius / 2, centerY, angle2radian(60), 800, new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 222;
        mBalls[2] = ball;

        ball = new Ball(-radius / 2, centerX + radius / 2, centerY, angle2radian(60), 600, new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 222;
        mBalls[3] = ball;

        ball = new Ball(radius / 2, centerX, centerY - radius / 2, angle2radian(60), 700, new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 200;
        mBalls[4] = ball;

        ball = new Ball(-radius / 2, centerX, centerY + radius / 2, angle2radian(60), 600,
                new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 200;
        mBalls[5] = ball;
        //
        ball = new Ball(-radius / 2, centerX + radius / 2, centerY - radius / 2, angle2radian(60), 600,
                new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 167;
        mBalls[6] = ball;

        ball = new Ball(radius / 2, centerX + radius / 3, centerY + radius / 2, angle2radian(60), 700,
                new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 222;
        mBalls[7] = ball;

        ball = new Ball(-radius / 2, centerX - radius / 3, centerY - radius / 2, angle2radian(50), 600,
                new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 210;
        mBalls[8] = ball;

        ball = new Ball(radius / 2, centerX - radius / 2, centerY + radius / 2, angle2radian(50), 700,
                new AccelerateInterpolator());
        ball.ballRadius = getBallRadius();
        ball.alpa = 210;
        mBalls[9] = ball;

        if (true) {
            int notNullCount = 0;
            for (Ball b : mBalls) {
                if (b != null) {
                    notNullCount++;
                }
            }
            if (notNullCount != BALL_LENGTH) {
                Assert.assertTrue("notNullCount = " + notNullCount, false);
            }
        }
    }

    private float angle2radian(float angle) {
        return (float) (angle * Math.PI / 180);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mWidth == 0 || mHeight == 0) {
            return;
        }
        if (mState == STATE_INVALID) {
            return;
        }

        AnimationTime.update();

        int radius = mRadius;
        int centerX = mWidth / 2;
        int centerY = mHeight / 2;

        if (mState == STATE_NORMAL) {
            canvas.drawRect(0, 0, mWidth, mHeight, mFillCirclePaint);
            drawShadow(canvas);
            drawFillCircle(centerX, centerY, radius, canvas);
            drawStrokeCircle(centerX, centerY, radius, canvas);
            drawCenterText(canvas);
            invalidate();
            return;
        }

        if (mState == STATE_CLEANING) {
            canvas.drawRect(0, 0, mWidth, mHeight, mFillCirclePaint);
            drawShadow(canvas);
            drawFillCircle(centerX, centerY, radius, canvas);
            drawStrokeCircle(centerX, centerY, radius, canvas);
            drawCenterText(canvas);
            boolean ok = !drawParticles(canvas);
            if (mCleanEnd != null) {
                boolean finish = !mCleanEnd.calculate(AnimationTime.get());
                if (finish && ok) {
                    mState = STATE_CLEANED;
                }
            }
            invalidate();
            return;
        }

        if (mState == STATE_CLEANED || mState == STATE_NOT_CLEAN) {
            canvas.drawRect(0, 0, mWidth, mHeight, mFillCirclePaint);
            boolean finish = !mArcAnimation.calculate(AnimationTime.get());
            mArcAnimation.draw(canvas, mStrokeCirclePaint, mCircleRect);
            if (finish) {
                mState = STATE_QUIT;
                drawBottomText(canvas);
                notifyAnimationEnd();
            }
            invalidate();
            return;
        }

        if (mState == STATE_QUIT) {
            if (mQuitAnim != null) {
                boolean finish = !mQuitAnim.calculate(AnimationTime.get());
                if (finish) {
                    mState = STATE_INVALID;
                    notifyQuit();
                    return;
                }
            }
            canvas.drawRect(0, 0, mWidth, mHeight, mFillCirclePaint);
            drawStrokeCircle(centerX, centerY, radius, canvas);
            drawRight(canvas);
            drawBottomText(canvas);
            invalidate();
        }

    }

    private void drawFillCircle(int centerX, int centerY, int radius, Canvas canvas) {
        canvas.drawCircle(centerX, centerY, radius, mFillCirclePaint);
    }

    int sep = 3;
    int alpha = 220;

    private void drawShadow(Canvas canvas) {
        alpha = alpha - sep;
        if (alpha < 100) {
            alpha = 100;
            sep *= -1;
        }

        if (alpha > 220) {
            alpha = 220;
            sep *= -1;
        }
        mAlphaPaint.setAlpha(alpha);
        canvas.drawBitmap(mShadowBitmap, mBitmapSrcRect, mBitmapRect, mAlphaPaint);
    }


    Rect mUnitTextBounds = new Rect();
    Rect mBigTextBounds = new Rect();
    Rect mSmallTextBounds = new Rect();

    private void drawCenterText(Canvas canvas) {

        mBigTextPaint.setTextSize(mBigTextSize);
        mBigTextPaint.getTextBounds(mBigText, 0, mBigText.length(), mBigTextBounds);
        mSmallTextPaint.getTextBounds(mUnitText, 0, mUnitText.length(), mUnitTextBounds);
        mSmallTextPaint.getTextBounds(mSmallText, 0, mSmallText.length(), mSmallTextBounds);

        int height = mBigTextBounds.height() + mSmallTextBounds.height() + 15;
        int width = Math.max((mBigTextBounds.width() + mUnitTextBounds.width()), mSmallTextBounds.width()) + 15;

        int translateX = mWidth / 2 - width / 2;
        int translateY = mHeight / 2 - height / 2;

        mBigTextRect.left = 0;
        mBigTextRect.top = 0;
        mBigTextRect.right = mBigTextBounds.width();
        mBigTextRect.bottom = mBigTextBounds.height();

        mUnitTextRect.left = mBigTextBounds.width() + 15;
        mUnitTextRect.top = mBigTextBounds.height() - mUnitTextBounds.height();
        mUnitTextRect.right = mBigTextBounds.width() + mUnitTextBounds.width() + 15;
        mUnitTextRect.bottom = mBigTextBounds.height();

        mSmallTextRect.left = 0;
        mSmallTextRect.top = mBigTextBounds.height() + 15;
        mSmallTextRect.right = width;
        mSmallTextRect.bottom = height + 15;

        canvas.save();
        canvas.translate(translateX, translateY);

        mBigTextPaint.setTextSize(mBigTextSize);
        drawText(canvas, mBigTextPaint, mBigTextRect, mBigText);
        drawText(canvas, mSmallTextPaint, mUnitTextRect, mUnitText);
        drawText(canvas, mSmallTextPaint, mSmallTextRect, mSmallText);

        canvas.restore();
    }

    private void drawBottomText(Canvas canvas) {
        RectF targetRect = mBottomTextRect;
        Paint paint = mBigTextPaint;
        paint.setTextSize(mBottomTextSize);
        drawText(canvas, paint, targetRect, mBottomText);
    }

    /**
     * 绘制文字
     *
     * @param canvas\
     * @param paint\
     * @param rect 绘制区域
     * @param text 文字
     */
    private void drawText(Canvas canvas, Paint paint, RectF rect, String text) {
        Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
        // 计算baseLine
        float baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        canvas.drawText(text, rect.centerX(), baseline, paint);
    }

    private void drawRight(Canvas canvas) {
        Path path = new Path();
        int d = mRadius * 2;
        path.moveTo((getWidth() - d) / 2 + d / 4 + d / 16, (getHeight() - d) / 2 + d / 2);
        path.lineTo((getWidth() - d) / 2 + d / 4 + d / 8 + d / 16, (getHeight() - d) / 2 + (d / 4) * 3 - d / 8);
        path.lineTo((getWidth() - d) / 2 + d / 2 + d / 4 - d / 8 + d / 16, (getHeight() - d) / 2 + d / 4 + d / 8);
        canvas.drawPath(path, mRightPaint);
    }

    // 绘制旋转的粒子
    private boolean drawParticles(Canvas canvas) {
        int size = mBallAnimationList.size();
        boolean update = false;
        for (int i = 0; i < size; i++) {
            boolean a = mBallAnimationList.get(i).calculate(AnimationTime.get());
            update |= a;
            if (!a) {
                mDelTemp.add(mBallAnimationList.get(i));
            }
        }
        mBallAnimationList.removeAll(mDelTemp);
        size = mBallAnimationList.size();
        for (int i = 0; i < size; i++) {
            mBallAnimationList.get(i).draw(canvas, mBallPaint);
        }
        return update;
    }

    private void notifyAnimationEnd() {
        mHandler.sendEmptyMessage(MSG_CLEAN_ANIM_FINISH);

    }

    private void notifyQuit() {
        mHandler.sendEmptyMessage(MSG_QUITE);
    }

    // 退出动画表象为让上一个画面短暂停一会
    private class QuitAnimation extends Animation {

        public QuitAnimation() {
            setInterpolator(new LinearInterpolator());
        }

        @Override
        protected void onCalculate(float progress) {}
    }

    private class ArcAnimation extends Animation {
        int start;
        int end;
        float progress;

        private ArcAnimation(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected void onCalculate(float progress) {
            this.progress = progress;
        }

        private float draw(Canvas canvas, Paint paint, RectF rectF) {
            float angle = (end - start) * progress;
            canvas.drawArc(rectF, -90, angle, false, paint);
            mRightPaint.setAlpha((int) (255 * progress));
            drawRight(canvas);
            return progress;
        }
    }


    private void drawStrokeCircle(int centerX, int centerY, int radius, Canvas canvas) {
        canvas.drawCircle(centerX, centerY, radius, mStrokeCirclePaint);
    }

    private class Ball {
        float r; // 半径
        int x; // x方向偏移
        int y; // y方向偏移
        float angle;// 弧度值角度
        int alpa; // 透明度
        int duration;// 时长
        float ballRadius;
        Interpolator interpolator; // 插值器

        public Ball(float r, int x, int y, float angle, int duration, Interpolator interpolator) {
            this.r = r;
            this.x = x;
            this.y = y;
            this.angle = angle;
            this.duration = duration;
            this.interpolator = interpolator;
        }
    }

    private class MyInterpolator implements Interpolator {

        @Override
        public float getInterpolation(float input) {
            return (float) ((float) 1 - Math.pow(1 - input, 5));
        }
    }

    private class BallAnimation extends Animation {

        Ball ball;
        float progress;

        private BallAnimation(Ball ball) {
            this.ball = ball;
            setDuration(ball.duration);
            setInterpolator(ball.interpolator);
            start();
        }

        @Override
        protected void onCalculate(float progress) {
            this.progress = progress;
        }

        private void draw(Canvas canvas, Paint paint) {
            involute(canvas, paint, progress, ball.angle, ball.r, ball.x, ball.y, ball.alpa, ball.ballRadius);
        }
    }

    // 绘制渐开线
    private void involute(Canvas canvas, Paint paint, float progress, float angle, float r, int startX, int startY,
            int alpa, float ballRadius) {
        paint.setAlpha((int) (alpa * (1 - progress)));
        float a = (float) ((1 - progress) * angle * Math.PI);
        float x = startX + (float) (r * (Math.cos(a) + a * Math.sin(a)));
        float y = startY + (float) (r * (Math.sin(a) - a * Math.cos(a)));
        canvas.drawCircle(x, y, ballRadius * (1 - progress) + 1, paint);
    }

    Random random = new Random();

    private float getBallRadius() {
        return random.nextFloat() * (mBallMaxRadius - mBallMinRadius) + mBallMinRadius;
    }

    private float convertDpToPixel(float dp, DisplayMetrics metrics) {
        return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
    }


    private void addBall(boolean two) {
        Random random = new Random();
        int i = random.nextInt(BALL_LENGTH);
        if (i >= BALL_LENGTH) {
            i = BALL_LENGTH - 1;
        }
        BallAnimation animation = new BallAnimation(mBalls[i]);
        mBallAnimationList.add(animation);
        if (two && i % 2 == 0) {
            i = random.nextInt(BALL_LENGTH);
            if (i >= BALL_LENGTH) {
                i = BALL_LENGTH - 1;
            }
            animation = new BallAnimation(mBalls[i]);
            mBallAnimationList.add(animation);
        }
    }

    private float mCleanStep;

    private void initHandler() {
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == MSG_CLEANING) {
                    if (mRemoveMessage) {
                        return;
                    }

                    if (mWidth == 0 || mHeight == 0) {
                        sendEmptyMessageDelayed(1, 100);
                        return;
                    }

                    mCleanSize -= mCleanStep;
                    if (mCleanSize < 0) {
                        mCleanSize = 0;
                    }
                    float b = (float) (Math.round(mCleanSize * 10)) / 10;
                    mBigText = Float.toString(b);

                    addBall(true);
                    sendEmptyMessageDelayed(MSG_CLEANING, 200);
                } else if (msg.what == MSG_CLEAN_ANIM_FINISH) {
                    if (mListener != null) {
                        mListener.onAnimationEnd();
                    }
                } else if (msg.what == MSG_QUITE) {
                    if (mListener != null) {
                        mListener.onQuit();
                    }
                }

            }
        };

    }

    public void startRun() {
        mState = STATE_CLEANING;
        mHandler.sendEmptyMessage(MSG_CLEANING);
        postInvalidate();
    }

    private CleanEnd mCleanEnd;

    private boolean mRemoveMessage;

    public void endRun() {
        mCleanEnd = new CleanEnd(mCleanSize);
        mCleanEnd.setDuration(500);
        mCleanEnd.setInterpolator(new LinearInterpolator());
        mCleanEnd.start();
        mRemoveMessage = true;
        mHandler.removeMessages(MSG_CLEANING);
        postInvalidate();
    }

    public void showResult() {
        mState = STATE_NOT_CLEAN;
        postInvalidate();
    }


    float mCleanSize;

    /**
     * 设置圆圈中间的两层文字
     *
     * @param size 圆圈中间大文字，上层 e.g. 100.0
     * @param unit 圆圈中间的小文字，下层 e.g. MB
     */
    public void setText(float size, String unit) {
        mCleanSize = size;
        resetCleanStep(size);

        if (unit != null) {
            this.mUnitText = unit;
        }

        mSmallText = "正在清理";

        mBottomText = "清理" + String.valueOf(size) + unit;
    }

    private void resetCleanStep(float size) {
        if (size <= 10) {
            mCleanStep = 0.2f;
            return;
        }
        if (size <= 20) {
            mCleanStep = 0.4f;
            return;
        }
        if (size <= 40) {
            mCleanStep = 0.6f;
            return;
        }
        if (size <= 100) {
            mCleanStep = 0.8f;
            return;
        }
        if (size <= 200) {
            mCleanStep = 2.2f;
            return;
        }
        if (size <= 400) {
            mCleanStep = 3.3f;
            return;
        }
        mCleanStep = 4.4f;
    }

    public void setBottomText(String text) {
        mBottomText = text;
    }

    public String getBottomText() {
        return mBottomText;
    }

    public void addListener(CleanViewCallback listener) {
        this.mListener = listener;
    }

    public interface CleanViewCallback {
        void onAnimationEnd();

        void onQuit();
    }

    private class CleanEnd extends Animation {

        private float curCleanSize;

        public CleanEnd(float curCleanSize) {
            this.curCleanSize = curCleanSize;
        }

        @Override
        protected void onCalculate(float progress) {
            float size = (1 - progress) * this.curCleanSize;
            float b = (float) (Math.round(size * 10)) / 10;
            mBigText = Float.toString(b);
            addBall(false);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return true;
    }
}
